package com.ck.client.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ck.client.dao.DeviceInfoMapper;
import com.ck.client.dao.DeviceUpgradeInfoMapper;
import com.ck.client.model.vo.DeviceOperationVO;
import com.ck.client.model.vo.DeviceUpgradeVO;
import com.ck.client.model.vo.ProgramPlayListVO;
import com.ck.client.model.vo.ProgramVO;
import com.ck.client.service.*;
import com.ck.client.service.async.AsyncService;
import com.ck.common.model.*;
import com.ck.common.model.bo.DeviceKeyMsg;
import com.ck.common.model.bo.DeviceReportBO;
import com.ck.common.model.bo.DeviceStateChangeBO;
import com.ck.core.cache.redis.RedisCacheDao;
import com.ck.core.constant.*;
import com.ck.core.constant.program.ProgramConstant;
import com.ck.core.util.BeanUtils;
import com.ck.core.util.UUIDUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * 客户端与服务端交互逻辑Service实现类
 */
@Service(value = "clientService")
public class ClientServiceImpl implements ClientService {
	private static Logger logger = LoggerFactory.getLogger(ClientServiceImpl.class);
	@Autowired
	private RedisCacheDao redisCacheDao;
	@Autowired
	private DeviceInfoService deviceInfoService;
	@Autowired
	private DeviceLogService deviceLogService;
	@Autowired
	private DeviceSettingService deviceSettingService;
	@Autowired
	private DeviceUpgradeService deviceUpgradeService;
	@Autowired
	private PollConfigService pollConfigService;
	@Autowired
	private ProgramService programService;
	@Autowired
    private ProgramDownloadService programDownloadService;
    @Autowired
    private DeviceInfoMapper deviceInfoMapper;
    @Autowired
	private DeviceUpgradeInfoMapper deviceUpgradeInfoMapper;
    @Autowired
	private AsyncService asyncService;
    @Autowired
    private JsonDataService jsonDataService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private ProgramReducedLogService programReducedLogService;
    @Autowired
	private BindService bindService;

	/**
	 * 键-zipUrl
	 */
	public static final String JSON_KEY_ZIP_URL = "zipUrl";

	/**
	 * 上传日志
	 * @param deviceCode
	 * @param url   文件地址
	 * @param type 日志类型 @see com.ck.constant.LogType
	 */
	@Override
	@Transactional( rollbackFor = Exception.class)
	public OperationResult<Object> uploadLog(String deviceCode,String url,String type) {
		if ( StringUtils.isBlank(url) || StringUtils.isBlank(type) ) {
			return OperationResult.newValidateFailOperationResult("url或type参数缺失！");
		}
		if ( StringUtils.isNotBlank(url) ) {
			String[] osbUrls = url.split(SymbolConstant.COMMA_EN);
			for (String osbUrl : osbUrls) {
				URL u;
				try {
					u = new URL(osbUrl);
					// 获取华为obs的url路径（文件名）
					StringBuilder name = new StringBuilder(type).append(SymbolConstant.UNDERLINE).append(u.getPath().substring(1));
					DeviceLog deviceLog = new DeviceLog();
					deviceLog.setPackageName(name.toString());
					deviceLog.setFileDownloadUrl(osbUrl);
					deviceLog.setLogType(type);
					deviceLog.setUploadTime(System.currentTimeMillis());
					deviceLog.setDeviceCode(deviceCode);
					deviceLogService.saveDeviceLog(deviceLog);
				} catch (MalformedURLException e) {
					logger.error("终端上传日志异常：【"+deviceCode+"】" +e.getMessage(),e);
					return OperationResult.newSystemErrorOperationResult();
				}
			}
		}
		return OperationResult.newSuccessOperationResult();
	}

	@Override
	public OperationResult<Object> getNewestSetting(String deviceCode) {
		OperationResult<Object> result = OperationResult.newSuccessOperationResult();
		DeviceSetting deviceSetting = deviceSettingService.getDeviceSetting(deviceCode);
		if ( deviceSetting != null ) {
			DeviceOperationVO operation = new DeviceOperationVO();
			BeanUtils.copyProperties(operation, deviceSetting, true);
			result.setData(operation);
		}
		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public OperationResult<Object> getNewestSettingReply(Long serialNo,String deviceCode) {

		// 1、先更新缓存
		try {
			DeviceStateChangeBO deviceStateBO = (DeviceStateChangeBO) redisCacheDao.getCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode);
			if ( serialNo != null && deviceStateBO != null && deviceStateBO.getNewSettingUpdateTime().equals(serialNo) ) {
				deviceStateBO.setNewSetting(null);
				deviceStateBO.setNewSettingUpdateTime(null);
				redisCacheDao.putCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode, deviceStateBO);
			}
		} catch (Exception e) {
			logger.error("终端设置信息反馈，更新缓存异常：【"+deviceCode+"】" + e.getMessage(),e);
		}

		// 2、更新数据库中的一次性设置
		DeviceSetting deviceSetting = deviceSettingService.getDeviceSetting(deviceCode);
		if ( deviceSetting != null ) {
			if (Boolean.TRUE.equals(deviceSetting.getRestartOnce())
					|| Boolean.TRUE.equals(deviceSetting.getShutDownOnce())) {
				deviceSetting.setRestartOnce(null);
				deviceSetting.setShutDownOnce(null);
				deviceSettingService.updateDeviceSetting(deviceSetting);
			}
		}
		return OperationResult.newSuccessOperationResult();
	}


	@Override
	public OperationResult<Object> getUpgrade(String deviceCode, String softwareVersionName,Integer softwareVersionCode, String firmwareVer) {
		if ( softwareVersionCode == null || StringUtils.isBlank(softwareVersionName)  || StringUtils.isBlank(firmwareVer) ) {
			return OperationResult.newValidateFailOperationResult("版本号参数缺失！");
		}
		OperationResult<Object> result = OperationResult.newSuccessOperationResult();
		DeviceSetting deviceSetting = deviceSettingService.getDeviceSetting(deviceCode);
		if ( deviceSetting != null ) {
			List<DeviceUpgradeVO> data = new ArrayList<>();
			if ( deviceSetting.getSoftwareUpgradeId() != null ) {
				DeviceUpgradeVO softwareUpgrade = deviceUpgradeService.getDeviceUpgrade(deviceSetting.getSoftwareUpgradeId());
				if ( softwareUpgrade != null && softwareUpgrade.getVersionCode().intValue() > softwareVersionCode.intValue() ) {
					transferMB2Byte(softwareUpgrade);
					data.add(softwareUpgrade);
				}
			}
			if ( deviceSetting.getFirmwareUpgradeId() != null ) {
				DeviceUpgradeVO firmwareUpgrade = deviceUpgradeService.getDeviceUpgrade(deviceSetting.getFirmwareUpgradeId());
				if (  firmwareUpgrade != null && !firmwareUpgrade.getVersionName().equals(firmwareVer) ) {
					transferMB2Byte(firmwareUpgrade);
					data.add(firmwareUpgrade);
				}
			}
			result.setData(data);
		}
		return result;
	}

	private void transferMB2Byte(DeviceUpgradeVO upgrade) {
		if ( StringUtils.isNotBlank(upgrade.getSize()) ) {
			BigDecimal size = new BigDecimal(upgrade.getSize());
			size = size.multiply(new BigDecimal(1024)).multiply(new BigDecimal(1024));
			upgrade.setSize(size.toPlainString());
		}
	}

	@Override
	@Transactional( rollbackFor = Exception.class)
	public OperationResult<Object> getUpgradeReply(Long serialNo, String deviceCode,String softwareVer, Integer softwareVerCode,String firmwareVer) {
		if ( (StringUtils.isBlank(softwareVer) && StringUtils.isBlank(firmwareVer) )) {
			return OperationResult.newValidateFailOperationResult("softwareVer或firmwareVer或版本号参数缺失！");
		}

		// 1、更新终端设置表的设置信息、终端表的升级时间信息
		DeviceSetting deviceSetting = deviceSettingService.getDeviceSetting(deviceCode);
		if ( deviceSetting != null ) {
			Long softwareUpdateTime = null;
			Long firmwareUpdateTime = null;
			boolean hasUpgrade = false;
			//原来的softwareUpgradeId
			Long oldSoftwareUpgradeId = null;
			if ( deviceSetting.getSoftwareUpgradeId() != null ) {
				// 当前设置信息理有apk升级配置，且当前传入的apk versionName，versionCode与设置信息一致时，做APK升级成功处理
				DeviceUpgradeVO softwareUpgrade = deviceUpgradeService.getDeviceUpgrade(deviceSetting.getSoftwareUpgradeId());
				if (  softwareUpgrade != null && softwareUpgrade.getVersionCode().intValue() == softwareVerCode.intValue() ) {
					hasUpgrade = true;
					oldSoftwareUpgradeId = deviceSetting.getSoftwareUpgradeId();
					// 清空设置信息
					deviceSetting.setSoftwareUpgradeId(null);
					softwareUpdateTime = System.currentTimeMillis();
				}
			}
			if ( deviceSetting.getFirmwareUpgradeId() != null ) {
				// 当前设置信息理有固件升级配置，且当前传入的固件版本与设置信息一致时，做固件升级成功处理
				DeviceUpgradeVO firmwareUpgrade = deviceUpgradeService.getDeviceUpgrade(deviceSetting.getFirmwareUpgradeId());
				if ( firmwareUpgrade.getVersionName().equals(firmwareVer) ) {
					hasUpgrade = true;
					// 清空设置信息
					deviceSetting.setFirmwareUpgradeId(null);
					firmwareUpdateTime = System.currentTimeMillis();
				}
			}
			if ( hasUpgrade ) {
				deviceSettingService.updateDeviceSetting(deviceSetting);
				deviceInfoService.updateDeviceUpgradeInfo(deviceCode, softwareVer, softwareUpdateTime, firmwareVer, firmwareUpdateTime);
				// 改变升级详情表的状态(根据id和versionCode)
				deviceUpgradeInfoMapper.updateStatusByDeviceUpgradeInfo(deviceCode,oldSoftwareUpgradeId, softwareVerCode);
			} else {
				deviceInfoService.updateDeviceUpgradeInfo(deviceCode, softwareVer, null, firmwareVer, null);
			}
		}

		// 2、更新缓存
		try {
			DeviceStateChangeBO deviceStateBO = (DeviceStateChangeBO) redisCacheDao.getCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode);
			if ( serialNo != null && deviceStateBO != null && deviceStateBO.getNewUpgradeUpdateTime() != null && deviceStateBO.getNewUpgradeUpdateTime().equals(serialNo) ) {
				deviceStateBO.setNewUpgrade(null);
				deviceStateBO.setNewUpgradeUpdateTime(null);
				redisCacheDao.putCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode, deviceStateBO);
			}
		} catch (Exception e) {
			logger.error("终端升级信息反馈，更新缓存异常：【"+deviceCode+"】" + e.getMessage(),e);
		}
		return OperationResult.newSuccessOperationResult();
	}

	@Override
	public OperationResult<Object> getNewestProgram(String deviceCode, Long residualCapacity) {
		if ( StringUtils.isBlank(deviceCode) ) {
			return OperationResult.newValidateFailOperationResult("deviceCode参数缺失！");
		}

		Device device = deviceInfoService.getDeviceInfoByCode(deviceCode);
		if(null == device){
			return OperationResult.newValidateFailOperationResult("终端尚未注册");
		}

		//获取终端分辨率
		String resolution = deviceInfoService.getDeviceResolution(deviceCode);

		logger.info("\n\t》》》获取最新节目 getNewestProgram 参数： "
				+ "\n\t》》》deviceCode：" + deviceCode
				+ "\n\t》》》residualCapacity：" + residualCapacity);

		Map<String, Object> data = new HashMap<>(1);
		OperationResult<Object> result = OperationResult.newSuccessOperationResult();
		/*
		 * 增量的节目
		 * 根据终端上报的剩余存储容量从新节目中按顺序取出合适的节目
		 * 比如新节目为1（200M）,2(200M),3(300M)  终端剩余存储容量为300M
		 * 那么就只能讲节目1下发给终端
		 *
		 * 1.同一时段可以有多个节目下发，终端下载的节目按照节目优先级排队，优先级相同的节目，按照下载下来时间排序
		 * 2.插播计划节目优先级最高，同一时间段，同一台机器只能下发一个插播计划
		 * 4.节目优先级排序（插播>普通）
		 */
		List<ProgramVO> newestProgramList = new ArrayList<>();
		//节目版本号
		List<String> newestProgramVersionList = new ArrayList<>();
		//当前时间戳
		Long currentMills = System.currentTimeMillis();

		//从数据库中获取未开始和已开始播放的节目
		List<ProgramVO> programListInDb = programService.getNewestProgram(deviceCode, currentMills);

		//不能存储终端存储容量
		long newProgramSizeCount = 0;
        for (ProgramVO aProgramListInDb : programListInDb) {
            if(null != aProgramListInDb.getProgramSize() && ((aProgramListInDb.getProgramSize() + newProgramSizeCount) <= residualCapacity)){
                newProgramSizeCount += aProgramListInDb.getProgramSize();
                newestProgramList.add(aProgramListInDb);
				newestProgramVersionList.add(aProgramListInDb.getProgramVersion());
            }
        }

		//除去已减播的素材后的素材列表
		List<ProgramPlayListVO> programSourceVOList = programService.getNewestSourcesByDeviceCode(deviceCode, newestProgramVersionList, resolution);

        //重构节目sourceInfo
        List<ProgramVO> newestProgramListNew = new ArrayList<>();
		for (ProgramVO programVO : newestProgramList) {
			JSONObject jsonInfoObj = new JSONObject();
			JSONArray sources = new JSONArray();
			if(CollectionUtils.isNotEmpty(programSourceVOList)){
				for (ProgramPlayListVO programPlayListVO : programSourceVOList) {
					if(programVO.getProgramVersion().equals(programPlayListVO.getProgramVersion())){
						JSONObject source = new JSONObject();
						source.put("fileName", programPlayListVO.getFileName());
						source.put("duration", programPlayListVO.getDuration());
						source.put("fileType", programPlayListVO.getFileType());
						source.put("md5", programPlayListVO.getMd5());
						source.put("url", programPlayListVO.getUrl());
						sources.add(source);
					}
				}
			}
			//无素材，则不下发节目给终端
			if(sources.isEmpty()){
			    continue;
            }
			jsonInfoObj.put(resolution, sources.toJSONString());
			programVO.setSourceInfo(jsonInfoObj);
            newestProgramListNew.add(programVO);
		}

//		//查询减播的素材，减播终端当前播放列表中的素材
//		List<String> programReducedSourceList = programReducedLogService.list(deviceCode, newestProgramVersionList);
//		logger.info("\n\t》》》已减播的素材：" + programReducedSourceList);
//
//		//处理节目素材，减播的素材清除
//        List<ProgramVO> newestProgramListHandled = handleSources(newestProgramList, programReducedSourceList, resolution);

		data.put("newProgram", newestProgramListNew);
		logger.info("\n\t》》》终端" + deviceCode + "最新节目列表：" + newestProgramListNew);
		result.setData(data);
		return result;
	}

	@Override
	public OperationResult<Object> getNewestProgramReply(Long serialNo, String deviceCode) {
		// 更新缓存
		try {
			DeviceStateChangeBO deviceStateBO = (DeviceStateChangeBO) redisCacheDao.getCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode);
			if ( serialNo != null && deviceStateBO != null && deviceStateBO.getNewProgramUpdateTime() != null && deviceStateBO.getNewProgramUpdateTime().equals(serialNo) ) {
				deviceStateBO.setNewProgram(null);
				deviceStateBO.setNewProgramUpdateTime(null);
				redisCacheDao.putCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode, deviceStateBO);
			}
		} catch (Exception e) {
			logger.error("终端最新节目信息反馈，更新缓存异常：【"+deviceCode+"】" + e.getMessage(),e);
		}
		return OperationResult.newSuccessOperationResult();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public OperationResult<Object> deviceRegister(String deviceCode, String deviceMac,
												  String intranetIP, String externalIP, String modelName,
												  String softwareVersion, String firmwareVersion,
												  String resolution) {
        // 根据序列号获取缓存中的关键信息
        DeviceKeyMsg deviceKeyMsg = (DeviceKeyMsg) redisCacheDao.getCache(CacheConstant.CACHE_NAME_DEVICE_KEY_MSG, deviceCode);
        // 如果缓存不存在，则从数据库获取一次
        if ( deviceKeyMsg == null ) {
            deviceKeyMsg = deviceInfoMapper.getDeviceKeyMsg(deviceCode);
        }

        // 这里不用做非空判断是因为拦截器已过滤掉非法设备，进入该方法的设备要么是首次从注册要么是二次绑定
        if ( deviceKeyMsg.getDeviceCode() == null ) {
            return doFirstRegist( deviceCode, deviceMac, intranetIP, externalIP, modelName,
                    softwareVersion, firmwareVersion,resolution);
        } else {
            return doSecondRegister(deviceCode,deviceMac,modelName,resolution);
        }


	}

	/**
	 * 重构素材json对象（将减播素材去除）
	 * @param newProgramList 节目集合
	 * @param programReducedSourceList 减播素材
	 * @param deviceResolution 终端分辨率
	 * @return 去掉已减播素材后的节目
	 */
	private List<ProgramVO> handleSources(List<ProgramVO> newProgramList, List<String> programReducedSourceList, String deviceResolution){
        List<ProgramVO> newProgramListHandled = new ArrayList<>();
	    if(StringUtils.isBlank(deviceResolution)){
	        return newProgramListHandled;
        }
        StringBuilder newestResource = new StringBuilder();
		if(CollectionUtils.isNotEmpty(newProgramList)){
			for (ProgramVO program: newProgramList ) {
				if(StringUtils.isNotBlank(program.getProgramInfo())){
					JSONObject jsonInfoObj = new JSONObject();
					JSONObject jsonObject = JSON.parseObject(program.getProgramInfo());
					if(null == jsonObject){
                        program.setSourceInfo(jsonInfoObj);
                        continue;
					}
					//遍历节目不同分辨率下的素材
                    for (String resolution : jsonObject.keySet()) {
                        String jsonContent = "";
                        JSONObject resolutionObj = jsonObject.getJSONObject(resolution);
                        if(null == resolutionObj){
                            jsonInfoObj.put(resolution, jsonContent);
                            continue;
                        }
                        jsonContent = getJsonDataInfo(resolutionObj);
                        if(StringUtils.isBlank(jsonContent)){
                            jsonInfoObj.put(resolution, "");
                            continue;
                        }
                        //只处理当前终端对应分辨率下素材
                        if(!resolution.equals(deviceResolution)){
                            continue;
                        }
                        //遍历终端分辨率对应的素材
                        JSONArray jsonArray = JSONArray.parseArray(jsonContent);
                        if(CollectionUtils.isEmpty(jsonArray)){
                            jsonInfoObj.put(resolution, "");
                            continue;
                        }
                        //剔除减播的素材后的素材集合
                        JSONArray jsonArrayNew = new JSONArray();
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONObject source = jsonArray.getJSONObject(i);
                            //减播的素材url和name同时满足时，清除
                            String sourceKey = program.getProgramVersion()
                                    + SymbolConstant.UNDERLINE + source.getString(JsonKeyEnum.URL.getValue())
                                    + SymbolConstant.UNDERLINE + source.getString(JsonKeyEnum.FILE_NAME.getValue());
                            //不在减播列表中则添加
                            if(!programReducedSourceList.contains(sourceKey)){
                                jsonArrayNew.add(source);
                                newestResource.append("\n\t").append(sourceKey);
                            }
                        }
                        if(CollectionUtils.isNotEmpty(jsonArrayNew)){
                            jsonContent = jsonArrayNew.toJSONString();
                        }
                        jsonInfoObj.put(resolution, jsonContent);
                    }
					program.setSourceInfo(jsonInfoObj);
				}
				newProgramListHandled.add(program);
			}
		}
        logger.info("\n\t》》》当前播放素材：" + newestResource.toString());
		return newProgramListHandled;
	}

    /**
     * 获取jsonContent
     * @param resolutionObj
     * @return
     */
	private String getJsonDataInfo(JSONObject resolutionObj){
	    if(null == resolutionObj){
	        return null;
        }
        String jsonContent = null;
        Long jsonId = resolutionObj.getLong(JsonKeyEnum.JSON_ID.getValue());
        if(null != jsonId){
            JsonData jsonData = jsonDataService.selectByPrimaryKey(jsonId);
            if(null != jsonData){
                //重新构造素材json数组字符串
                jsonContent = jsonData.getJsonContent();
            }
        }
        return jsonContent;
    }

    /**
     * 二次绑定，将解绑状态置为绑定状态，且设置token值
     *
	 * @param deviceCode
	 * @return
     */
    private OperationResult<Object> doSecondRegister( String deviceCode,String deviceMac,String deviceModel,String resolution) {
        String token = UUIDUtils.getUUIDString();
		Long deviceGroupId = bindService.getDeviceGroupWithStore(deviceCode);
        // 1、更新device表的绑定状态
        deviceInfoService.secondRegister(deviceCode,token,deviceGroupId);

        // 2、每次绑定当作全新设备初始化处理，需要录入，机型，mac等字段
		deviceInfoService.setDeviceInfo(deviceCode,deviceMac,deviceModel,resolution);

        // 3、绑定成功后写入缓存
        putCacheAfterSuccess(deviceCode,token);

        return OperationResult.newSuccessOperationResult(token);
    }

	private void putCacheAfterSuccess(String deviceCode, String token) {
		try {
			DeviceKeyMsg deviceKeyMsg = new DeviceKeyMsg(deviceCode,token,BusinessConstant.DEVICE_BIND);
			redisCacheDao.putCache(CacheConstant.CACHE_NAME_DEVICE_KEY_MSG, deviceCode, deviceKeyMsg);
		} catch (Exception e) {
			logger.error("设备关键信息写入缓存时异常：【"+deviceCode+"】" + e.getMessage(),e);
		}
	}

	/**
     * 设备首次注册逻辑
     * @param deviceCode
     * @param deviceMac
     * @param modelName
     * @param softwareVersion
     * @param firmwareVersion
     * @param resolution
	 * @return
     */
    private OperationResult<Object> doFirstRegist( String deviceCode, String deviceMac,String intranetIP, String externalIP,
												   String modelName, String softwareVersion, String firmwareVersion, String resolution) {
        // 校验设备信息
        String checkMsg = checkDeviceRegisterParam(deviceCode, deviceMac, modelName, softwareVersion, firmwareVersion);
        if ( StringUtils.isNotBlank(checkMsg) ) {
            return OperationResult.newValidateFailOperationResult(checkMsg);
        }

        Long now = System.currentTimeMillis();

        // 新增终端基础信息表
        String token = UUIDUtils.getUUIDString();
        Long deviceGroupId = bindService.getDeviceGroupWithStore(deviceCode);
        Device device = new Device(deviceCode,deviceGroupId, now,now, intranetIP,externalIP, BusinessConstant.DEVICE_INFO_STATUS_ON_LINE, softwareVersion, null,firmwareVersion,null,now,BusinessConstant.DEVICE_BIND,token);

        deviceInfoService.register(device);

        // 设置设备的机型、分辨率、mac地址等附属信息
		deviceInfoService.setDeviceInfo(deviceCode,deviceMac,modelName,resolution);

        // 新增终端设置表
        DeviceSetting deviceSetting = new DeviceSetting( deviceCode, now);
        deviceSettingService.register(deviceSetting);

        OperationResult<Object> operationResult = OperationResult.newSuccessOperationResult();
        operationResult.setData(token);
        putCacheAfterSuccess(deviceCode,token);
        return operationResult;
    }

    /**
	 * 终端上传节目下载状态
	 * @param deviceCode 终端code
	 * @param downloadProgramVersion 下载节目的版本号
	 * @param state 下载状态
	 * @param failureReason 失败原因（如有）
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public OperationResult<Object> uploadProgramDownloadStatus(String deviceCode,String downloadProgramVersion, Integer state, String failureReason) {

		// 检查节目是否存在
		ProgramVO programInfo = programService.getProgramInfoByVersion(downloadProgramVersion);
		if (programInfo == null) {
			return OperationResult.newValidateFailOperationResult("未找到对应的节目数据");
		}
		long currentTimeMillis = System.currentTimeMillis();
		Sysconfig sysconfig = sysConfigService.getByType(SysConfigNameEnum.ALLOW_SUCCESS_PUSH_LATEST_TIME);
		// 获取当前节目下载信息
		ProgramDownload programDownload = programDownloadService.getProgramDownloadByCodeAndXcVersion(deviceCode, downloadProgramVersion);
		if (programDownload == null) {
			programDownload = new ProgramDownload();
			programDownload.setDeviceCode(deviceCode);
			programDownload.setProgramVersion(downloadProgramVersion);
            long pushTime = (programInfo.getPushTime() == null ? 0 : programInfo.getPushTime());
            long lastAllowTimeInDbMills = ProgramConstant.DEFAULT_ALLOW_SUCCESS_PUSH_LATEST_TIME * ProgramConstant.UNIT_HOUR_TO_MILLS;
			// 允许最晚发送成功时间（终端开始调用下载接口），单位：毫秒
			programDownload.setAllowSuccessPushLatestTime(pushTime
					+ (sysconfig == null ? lastAllowTimeInDbMills : Long.parseLong(sysconfig.getValue()) * ProgramConstant.UNIT_HOUR_TO_MILLS));
		}
		programDownload.setUpdateTime(currentTimeMillis);
		programDownload.setDownloadStatus(state);
		programDownload.setDownloadFailReason(StringUtils.isNotBlank(failureReason) ? failureReason : null);
		// 0正常，1逻辑删除
		programDownload.setDataStatus(0);
		// 如果当前节目下载信息不存在则插入一条新数据，存在则修改旧数据
		if(programDownload.getProgramDownloadId() == null) {
			programDownloadService.saveProgramDownload(programDownload);
		} else {
			programDownloadService.updateProgramDownload(programDownload);
		}

		// 记录失败日志记录
		if(BusinessConstant.PROGRAM_DOWNLOAD_FAIL == state) {
			programDownloadService.saveDownloadFailLog(deviceCode, downloadProgramVersion, failureReason);
		}

		return new OperationResult<>(ClientConstant.CODE_SUCCESS, "上报成功");
	}

	@Override
	public OperationResult<Object> deviceReport(DeviceReportBO deviceReport) {

		OperationResult<Object> result = OperationResult.newSuccessOperationResult();
		Map<String,Object> data = new HashMap<>();
		// 系统时间
		data.put("sysDate", System.currentTimeMillis());
		result.setData(data);

		// 查询是否有设备状态变更
		try {
			DeviceStateChangeBO deviceStateBO = (DeviceStateChangeBO) redisCacheDao.getCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceReport.getDeviceCode());
			data.put("newChange",deviceStateBO);
		} catch (Exception e) {
			logger.error("终端上报信息时，查询设备状态变更缓存信息异常：" + e.getMessage(),e);
		}

		// 查询轮询配置信息
		try {
			@SuppressWarnings("unchecked")
			List<PollConfig> configs = (List<PollConfig>)redisCacheDao.getCache(CacheConstant.CACHE_NAME_POLL_CONFIG, "POLL_CONFIG");
			if ( configs == null ) {
				configs = pollConfigService.getAllConfig();
				redisCacheDao.putCache(CacheConstant.CACHE_NAME_POLL_CONFIG, "POLL_CONFIG",configs);
				redisCacheDao.expire(CacheConstant.CACHE_NAME_POLL_CONFIG, 2L, TimeUnit.HOURS);
			}
			data.put("pollConfig", configs);
		} catch (Exception e) {
			logger.error("终端上报信息时，查询轮询配置信息异常：" + e.getMessage(),e);
		}

		// TODO 预留字段，token下发
		data.put("token",null);

		// 开启一个异步线程将此次上报信息同步到数据库
		asyncService.deviceReport(deviceReport);

		return result;
	}

	private String checkDeviceRegisterParam( String deviceCode, String deviceMac, String modelName, String softwareVersion, String firmwareVersion){
		String errorMsg = "";
		if (StringUtils.isBlank(deviceCode)) {
			errorMsg = "deviceCode不能为空";
			return errorMsg;
		}
		if (StringUtils.isBlank(deviceMac)) {
			errorMsg = "Mac地址不能为空";
			return errorMsg;
		}
		if (StringUtils.isBlank(modelName)) {
			errorMsg = "设备类型不能为空";
			return errorMsg;
		}
		if (StringUtils.isBlank(softwareVersion)) {
			errorMsg = "软件版本不能为空";
			return errorMsg;
		}
		if (StringUtils.isBlank(firmwareVersion)) {
			errorMsg = "固件版本不能为空";
			return errorMsg;
		}
		return errorMsg;
	}

	@Override
	public OperationResult<Object> settingSync(Integer volume, String deviceCode) {
		DeviceSetting deviceSetting = deviceSettingService.getDeviceSetting(deviceCode);
		if ( deviceSetting != null ) {
			deviceSetting.setDeviceVolume(volume);
			deviceSettingService.updateDeviceSetting(deviceSetting);
		}
		return OperationResult.newSuccessOperationResult();
	}

}
